package com.jt.aop;

import com.jt.annotation.CacheFind;
import com.jt.util.ObjectMapperUtil;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.ShardedJedis;

import java.util.Arrays;

@Component  //将对象交给Spring容器管理
@Aspect     //标识我是一个切面
public class CacheAOP {
    @Autowired
   // private ShardedJedis jedis;
    private JedisCluster jedis;

    /**
     * 拦截@CacheFind注解的方法
     * 通知选择:缓存的实现应该选用around通知
     * 过程:
     * 1.动态生成redis中的key 用户填写的key+用户提交的参数
     */
    @Around("@annotation(cacheFind)")
    public Object around(ProceedingJoinPoint jp, CacheFind cacheFind) {
        //1.获取用户注解中填写的内容
        String key = cacheFind.Key();
        //2.获取目标对象的参数
        Object[] array = jp.getArgs();
        key += "::" + Arrays.toString(array);
        //3.从redis中获取数据
        Object result = null;
        if (jedis.exists(key)) {
            String json = jedis.get(key);
            //获取返回值类型
            MethodSignature methodSignature = (MethodSignature) jp.getSignature();
            Class targetClass = methodSignature.getReturnType();
            result = ObjectMapperUtil.toObject(json, targetClass);
            System.out.println("缓存获取数据");
        } else {
            //key不存在,直接查询使用
            try {
                result = jp.proceed();
                String json = ObjectMapperUtil.toJson(result);
                if (cacheFind.seconds() > 0) {
                    jedis.setex(key, cacheFind.seconds(), json);
                } else {
                    jedis.set(key, json);
                }
                System.out.println("第一次查询");
            } catch (Throwable throwable) {
                throwable.printStackTrace();
                throw new RuntimeException(throwable);
            }
        }
        return result;
    }
    @Before("@annotation(com.jt.annotation.CacheFind)")
    public void before(JoinPoint joinPoint){
       Object target = joinPoint.getTarget();
       Object[] args = joinPoint.getArgs();
       String targetName = joinPoint.getSignature().getDeclaringTypeName();//获取目标对象的名字
        //获取目标对象的类型
        Class targetClass = joinPoint.getSignature().getDeclaringType();
        //获取目标对象的类型
        String methodName = joinPoint.getSignature().getName();
        System.out.println(target);
        System.out.println(args);
        System.out.println(targetName);
        System.out.println(targetClass);
        System.out.println(target);
    }

    /**
     * AOP = 切入点表达式 + 通知方法
     */
    /**
     * 需求:
     * 1.拦截itemCatServiceImpl的bean
     * 2.拦截com.jt.service下的所有的类
     * 3.拦截com.jt.service下的所有类及方法
     * 3.1 拦截com.jt.service的所有的类,返回值类型为int类型的,并且add开头的方法
     * 且参数为一个 为string类型
     */
    //@Pointcut(value = "bean(itemCatServiceImpl)")
    // @Pointcut("within(com.jt.service.*)")
    //拦截com.jt.service下的所有类及所有方法的任意参数类型
    //@Pointcut("execution(* com.jt.service..*.*(..))")
   /* @Pointcut("execution(int com.jt.service..*.find*(..))")
    public void pointCut() {
    }

    //定义前置通知
    @Before("pointCut()")
    public void before() {
        System.out.println("我是前置通知");
    }*/

}
